home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tcl8.0 / generic / tclGetDate.y < prev    next >
Encoding:
Text File  |  1997-08-15  |  26.2 KB  |  959 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tclGetDate.y --
  3.  *
  4.  *    Contains yacc grammar for parsing date and time strings.
  5.  *    The output of this file should be the file tclDate.c which
  6.  *    is used directly in the Tcl sources.
  7.  *
  8.  * Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans.
  9.  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * SCCS: @(#) tclGetDate.y 1.34 97/02/03 14:53:54
  15.  */
  16.  
  17. %{
  18. /* 
  19.  * tclDate.c --
  20.  *
  21.  *    This file is generated from a yacc grammar defined in
  22.  *    the file tclGetDate.y.  It should not be edited directly.
  23.  *
  24.  * Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans.
  25.  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
  26.  *
  27.  * See the file "license.terms" for information on usage and redistribution
  28.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  29.  *
  30.  * SCCSID
  31.  */
  32.  
  33. #include "tclInt.h"
  34. #include "tclPort.h"
  35.  
  36. #ifdef MAC_TCL
  37. #   define EPOCH           1904
  38. #   define START_OF_TIME   1904
  39. #   define END_OF_TIME     2039
  40. #else
  41. #   define EPOCH           1970
  42. #   define START_OF_TIME   1902
  43. #   define END_OF_TIME     2037
  44. #endif
  45.  
  46. /*
  47.  * The offset of tm_year of struct tm returned by localtime, gmtime, etc.
  48.  * I don't know how universal this is; K&R II, the NetBSD manpages, and
  49.  * ../compat/strftime.c all agree that tm_year is the year-1900.  However,
  50.  * some systems may have a different value.  This #define should be the
  51.  * same as in ../compat/strftime.c.
  52.  */
  53. #define TM_YEAR_BASE 1900
  54.  
  55. #define HOUR(x)         ((int) (60 * x))
  56. #define SECSPERDAY      (24L * 60L * 60L)
  57.  
  58.  
  59. /*
  60.  *  An entry in the lexical lookup table.
  61.  */
  62. typedef struct _TABLE {
  63.     char        *name;
  64.     int         type;
  65.     time_t      value;
  66. } TABLE;
  67.  
  68.  
  69. /*
  70.  *  Daylight-savings mode:  on, off, or not yet known.
  71.  */
  72. typedef enum _DSTMODE {
  73.     DSTon, DSToff, DSTmaybe
  74. } DSTMODE;
  75.  
  76. /*
  77.  *  Meridian:  am, pm, or 24-hour style.
  78.  */
  79. typedef enum _MERIDIAN {
  80.     MERam, MERpm, MER24
  81. } MERIDIAN;
  82.  
  83.  
  84. /*
  85.  *  Global variables.  We could get rid of most of these by using a good
  86.  *  union as the yacc stack.  (This routine was originally written before
  87.  *  yacc had the %union construct.)  Maybe someday; right now we only use
  88.  *  the %union very rarely.
  89.  */
  90. static char     *yyInput;
  91. static DSTMODE  yyDSTmode;
  92. static time_t   yyDayOrdinal;
  93. static time_t   yyDayNumber;
  94. static int      yyHaveDate;
  95. static int      yyHaveDay;
  96. static int      yyHaveRel;
  97. static int      yyHaveTime;
  98. static int      yyHaveZone;
  99. static time_t   yyTimezone;
  100. static time_t   yyDay;
  101. static time_t   yyHour;
  102. static time_t   yyMinutes;
  103. static time_t   yyMonth;
  104. static time_t   yySeconds;
  105. static time_t   yyYear;
  106. static MERIDIAN yyMeridian;
  107. static time_t   yyRelMonth;
  108. static time_t   yyRelSeconds;
  109.  
  110.  
  111. /*
  112.  * Prototypes of internal functions.
  113.  */
  114. static void    yyerror _ANSI_ARGS_((char *s));
  115. static time_t    ToSeconds _ANSI_ARGS_((time_t Hours, time_t Minutes,
  116.             time_t Seconds, MERIDIAN Meridian));
  117. static int    Convert _ANSI_ARGS_((time_t Month, time_t Day, time_t Year,
  118.             time_t Hours, time_t Minutes, time_t Seconds,
  119.             MERIDIAN Meridia, DSTMODE DSTmode, time_t *TimePtr));
  120. static time_t    DSTcorrect _ANSI_ARGS_((time_t Start, time_t Future));
  121. static time_t    RelativeDate _ANSI_ARGS_((time_t Start, time_t DayOrdinal,
  122.             time_t DayNumber));
  123. static int    RelativeMonth _ANSI_ARGS_((time_t Start, time_t RelMonth,
  124.             time_t *TimePtr));
  125. static int    LookupWord _ANSI_ARGS_((char *buff));
  126. static int    yylex _ANSI_ARGS_((void));
  127.  
  128. int
  129. yyparse _ANSI_ARGS_((void));
  130. %}
  131.  
  132. %union {
  133.     time_t              Number;
  134.     enum _MERIDIAN      Meridian;
  135. }
  136.  
  137. %token  tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
  138. %token  tSEC_UNIT tSNUMBER tUNUMBER tZONE tEPOCH tDST
  139.  
  140. %type   <Number>        tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT tDST
  141. %type   <Number>        tSEC_UNIT tSNUMBER tUNUMBER tZONE
  142. %type   <Meridian>      tMERIDIAN o_merid
  143.  
  144. %%
  145.  
  146. spec    : /* NULL */
  147.         | spec item
  148.         ;
  149.  
  150. item    : time {
  151.             yyHaveTime++;
  152.         }
  153.         | zone {
  154.             yyHaveZone++;
  155.         }
  156.         | date {
  157.             yyHaveDate++;
  158.         }
  159.         | day {
  160.             yyHaveDay++;
  161.         }
  162.         | rel {
  163.             yyHaveRel++;
  164.         }
  165.         | number
  166.         ;
  167.  
  168. time    : tUNUMBER tMERIDIAN {
  169.             yyHour = $1;
  170.             yyMinutes = 0;
  171.             yySeconds = 0;
  172.             yyMeridian = $2;
  173.         }
  174.         | tUNUMBER ':' tUNUMBER o_merid {
  175.             yyHour = $1;
  176.             yyMinutes = $3;
  177.             yySeconds = 0;
  178.             yyMeridian = $4;
  179.         }
  180.         | tUNUMBER ':' tUNUMBER tSNUMBER {
  181.             yyHour = $1;
  182.             yyMinutes = $3;
  183.             yyMeridian = MER24;
  184.             yyDSTmode = DSToff;
  185.             yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
  186.         }
  187.         | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
  188.             yyHour = $1;
  189.             yyMinutes = $3;
  190.             yySeconds = $5;
  191.             yyMeridian = $6;
  192.         }
  193.         | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
  194.             yyHour = $1;
  195.             yyMinutes = $3;
  196.             yySeconds = $5;
  197.             yyMeridian = MER24;
  198.             yyDSTmode = DSToff;
  199.             yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
  200.         }
  201.         ;
  202.  
  203. zone    : tZONE tDST {
  204.             yyTimezone = $1;
  205.             yyDSTmode = DSTon;
  206.         }
  207.         | tZONE {
  208.             yyTimezone = $1;
  209.             yyDSTmode = DSToff;
  210.         }
  211.         | tDAYZONE {
  212.             yyTimezone = $1;
  213.             yyDSTmode = DSTon;
  214.         }
  215.         ;
  216.  
  217. day     : tDAY {
  218.             yyDayOrdinal = 1;
  219.             yyDayNumber = $1;
  220.         }
  221.         | tDAY ',' {
  222.             yyDayOrdinal = 1;
  223.             yyDayNumber = $1;
  224.         }
  225.         | tUNUMBER tDAY {
  226.             yyDayOrdinal = $1;
  227.             yyDayNumber = $2;
  228.         }
  229.         ;
  230.  
  231. date    : tUNUMBER '/' tUNUMBER {
  232.             yyMonth = $1;
  233.             yyDay = $3;
  234.         }
  235.         | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
  236.             yyMonth = $1;
  237.             yyDay = $3;
  238.             yyYear = $5;
  239.         }
  240.         | tMONTH tUNUMBER {
  241.             yyMonth = $1;
  242.             yyDay = $2;
  243.         }
  244.         | tMONTH tUNUMBER ',' tUNUMBER {
  245.             yyMonth = $1;
  246.             yyDay = $2;
  247.             yyYear = $4;
  248.         }
  249.         | tUNUMBER tMONTH {
  250.             yyMonth = $2;
  251.             yyDay = $1;
  252.         }
  253.           | tEPOCH {
  254.                 yyMonth = 1;
  255.                 yyDay = 1;
  256.                 yyYear = EPOCH;
  257.           }
  258.         | tUNUMBER tMONTH tUNUMBER {
  259.             yyMonth = $2;
  260.             yyDay = $1;
  261.             yyYear = $3;
  262.         }
  263.         ;
  264.  
  265. rel     : relunit tAGO {
  266.             yyRelSeconds = -yyRelSeconds;
  267.             yyRelMonth = -yyRelMonth;
  268.         }
  269.         | relunit
  270.         ;
  271.  
  272. relunit : tUNUMBER tMINUTE_UNIT {
  273.             yyRelSeconds += $1 * $2 * 60L;
  274.         }
  275.         | tSNUMBER tMINUTE_UNIT {
  276.             yyRelSeconds += $1 * $2 * 60L;
  277.         }
  278.         | tMINUTE_UNIT {
  279.             yyRelSeconds += $1 * 60L;
  280.         }
  281.         | tSNUMBER tSEC_UNIT {
  282.             yyRelSeconds += $1;
  283.         }
  284.         | tUNUMBER tSEC_UNIT {
  285.             yyRelSeconds += $1;
  286.         }
  287.         | tSEC_UNIT {
  288.             yyRelSeconds++;
  289.         }
  290.         | tSNUMBER tMONTH_UNIT {
  291.             yyRelMonth += $1 * $2;
  292.         }
  293.         | tUNUMBER tMONTH_UNIT {
  294.             yyRelMonth += $1 * $2;
  295.         }
  296.         | tMONTH_UNIT {
  297.             yyRelMonth += $1;
  298.         }
  299.         ;
  300.  
  301. number  : tUNUMBER
  302.     {
  303.     if (yyHaveTime && yyHaveDate && !yyHaveRel) {
  304.         yyYear = $1;
  305.     } else {
  306.         yyHaveTime++;
  307.         if ($1 < 100) {
  308.         yyHour = 0;
  309.         yyMinutes = $1;
  310.         } else {
  311.         yyHour = $1 / 100;
  312.         yyMinutes = $1 % 100;
  313.         }
  314.         yySeconds = 0;
  315.         yyMeridian = MER24;
  316.     }
  317.     }
  318. ;
  319.  
  320. o_merid : /* NULL */ {
  321.             $$ = MER24;
  322.         }
  323.         | tMERIDIAN {
  324.             $$ = $1;
  325.         }
  326.         ;
  327.  
  328. %%
  329.  
  330. /*
  331.  * Month and day table.
  332.  */
  333. static TABLE    MonthDayTable[] = {
  334.     { "january",        tMONTH,  1 },
  335.     { "february",       tMONTH,  2 },
  336.     { "march",          tMONTH,  3 },
  337.     { "april",          tMONTH,  4 },
  338.     { "may",            tMONTH,  5 },
  339.     { "june",           tMONTH,  6 },
  340.     { "july",           tMONTH,  7 },
  341.     { "august",         tMONTH,  8 },
  342.     { "september",      tMONTH,  9 },
  343.     { "sept",           tMONTH,  9 },
  344.     { "october",        tMONTH, 10 },
  345.     { "november",       tMONTH, 11 },
  346.     { "december",       tMONTH, 12 },
  347.     { "sunday",         tDAY, 0 },
  348.     { "monday",         tDAY, 1 },
  349.     { "tuesday",        tDAY, 2 },
  350.     { "tues",           tDAY, 2 },
  351.     { "wednesday",      tDAY, 3 },
  352.     { "wednes",         tDAY, 3 },
  353.     { "thursday",       tDAY, 4 },
  354.     { "thur",           tDAY, 4 },
  355.     { "thurs",          tDAY, 4 },
  356.     { "friday",         tDAY, 5 },
  357.     { "saturday",       tDAY, 6 },
  358.     { NULL }
  359. };
  360.  
  361. /*
  362.  * Time units table.
  363.  */
  364. static TABLE    UnitsTable[] = {
  365.     { "year",           tMONTH_UNIT,    12 },
  366.     { "month",          tMONTH_UNIT,    1 },
  367.     { "fortnight",      tMINUTE_UNIT,   14 * 24 * 60 },
  368.     { "week",           tMINUTE_UNIT,   7 * 24 * 60 },
  369.     { "day",            tMINUTE_UNIT,   1 * 24 * 60 },
  370.     { "hour",           tMINUTE_UNIT,   60 },
  371.     { "minute",         tMINUTE_UNIT,   1 },
  372.     { "min",            tMINUTE_UNIT,   1 },
  373.     { "second",         tSEC_UNIT,      1 },
  374.     { "sec",            tSEC_UNIT,      1 },
  375.     { NULL }
  376. };
  377.  
  378. /*
  379.  * Assorted relative-time words.
  380.  */
  381. static TABLE    OtherTable[] = {
  382.     { "tomorrow",       tMINUTE_UNIT,   1 * 24 * 60 },
  383.     { "yesterday",      tMINUTE_UNIT,   -1 * 24 * 60 },
  384.     { "today",          tMINUTE_UNIT,   0 },
  385.     { "now",            tMINUTE_UNIT,   0 },
  386.     { "last",           tUNUMBER,       -1 },
  387.     { "this",           tMINUTE_UNIT,   0 },
  388.     { "next",           tUNUMBER,       2 },
  389. #if 0
  390.     { "first",          tUNUMBER,       1 },
  391. /*  { "second",         tUNUMBER,       2 }, */
  392.     { "third",          tUNUMBER,       3 },
  393.     { "fourth",         tUNUMBER,       4 },
  394.     { "fifth",          tUNUMBER,       5 },
  395.     { "sixth",          tUNUMBER,       6 },
  396.     { "seventh",        tUNUMBER,       7 },
  397.     { "eighth",         tUNUMBER,       8 },
  398.     { "ninth",          tUNUMBER,       9 },
  399.     { "tenth",          tUNUMBER,       10 },
  400.     { "eleventh",       tUNUMBER,       11 },
  401.     { "twelfth",        tUNUMBER,       12 },
  402. #endif
  403.     { "ago",            tAGO,   1 },
  404.     { "epoch",          tEPOCH,   0 },
  405.     { NULL }
  406. };
  407.  
  408. /*
  409.  * The timezone table.  (Note: This table was modified to not use any floating
  410.  * point constants to work around an SGI compiler bug).
  411.  */
  412. static TABLE    TimezoneTable[] = {
  413.     { "gmt",    tZONE,     HOUR( 0) },      /* Greenwich Mean */
  414.     { "ut",     tZONE,     HOUR( 0) },      /* Universal (Coordinated) */
  415.     { "utc",    tZONE,     HOUR( 0) },
  416.     { "wet",    tZONE,     HOUR( 0) } ,     /* Western European */
  417.     { "bst",    tDAYZONE,  HOUR( 0) },      /* British Summer */
  418.     { "wat",    tZONE,     HOUR( 1) },      /* West Africa */
  419.     { "at",     tZONE,     HOUR( 2) },      /* Azores */
  420. #if     0
  421.     /* For completeness.  BST is also British Summer, and GST is
  422.      * also Guam Standard. */
  423.     { "bst",    tZONE,     HOUR( 3) },      /* Brazil Standard */
  424.     { "gst",    tZONE,     HOUR( 3) },      /* Greenland Standard */
  425. #endif
  426.     { "nft",    tZONE,     HOUR( 7/2) },    /* Newfoundland */
  427.     { "nst",    tZONE,     HOUR( 7/2) },    /* Newfoundland Standard */
  428.     { "ndt",    tDAYZONE,  HOUR( 7/2) },    /* Newfoundland Daylight */
  429.     { "ast",    tZONE,     HOUR( 4) },      /* Atlantic Standard */
  430.     { "adt",    tDAYZONE,  HOUR( 4) },      /* Atlantic Daylight */
  431.     { "est",    tZONE,     HOUR( 5) },      /* Eastern Standard */
  432.     { "edt",    tDAYZONE,  HOUR( 5) },      /* Eastern Daylight */
  433.     { "cst",    tZONE,     HOUR( 6) },      /* Central Standard */
  434.     { "cdt",    tDAYZONE,  HOUR( 6) },      /* Central Daylight */
  435.     { "mst",    tZONE,     HOUR( 7) },      /* Mountain Standard */
  436.     { "mdt",    tDAYZONE,  HOUR( 7) },      /* Mountain Daylight */
  437.     { "pst",    tZONE,     HOUR( 8) },      /* Pacific Standard */
  438.     { "pdt",    tDAYZONE,  HOUR( 8) },      /* Pacific Daylight */
  439.     { "yst",    tZONE,     HOUR( 9) },      /* Yukon Standard */
  440.     { "ydt",    tDAYZONE,  HOUR( 9) },      /* Yukon Daylight */
  441.     { "hst",    tZONE,     HOUR(10) },      /* Hawaii Standard */
  442.     { "hdt",    tDAYZONE,  HOUR(10) },      /* Hawaii Daylight */
  443.     { "cat",    tZONE,     HOUR(10) },      /* Central Alaska */
  444.     { "ahst",   tZONE,     HOUR(10) },      /* Alaska-Hawaii Standard */
  445.     { "nt",     tZONE,     HOUR(11) },      /* Nome */
  446.     { "idlw",   tZONE,     HOUR(12) },      /* International Date Line West */
  447.     { "cet",    tZONE,    -HOUR( 1) },      /* Central European */
  448.     { "met",    tZONE,    -HOUR( 1) },      /* Middle European */
  449.     { "mewt",   tZONE,    -HOUR( 1) },      /* Middle European Winter */
  450.     { "mest",   tDAYZONE, -HOUR( 1) },      /* Middle European Summer */
  451.     { "swt",    tZONE,    -HOUR( 1) },      /* Swedish Winter */
  452.     { "sst",    tDAYZONE, -HOUR( 1) },      /* Swedish Summer */
  453.     { "fwt",    tZONE,    -HOUR( 1) },      /* French Winter */
  454.     { "fst",    tDAYZONE, -HOUR( 1) },      /* French Summer */
  455.     { "eet",    tZONE,    -HOUR( 2) },      /* Eastern Europe, USSR Zone 1 */
  456.     { "bt",     tZONE,    -HOUR( 3) },      /* Baghdad, USSR Zone 2 */
  457.     { "it",     tZONE,    -HOUR( 7/2) },    /* Iran */
  458.     { "zp4",    tZONE,    -HOUR( 4) },      /* USSR Zone 3 */
  459.     { "zp5",    tZONE,    -HOUR( 5) },      /* USSR Zone 4 */
  460.     { "ist",    tZONE,    -HOUR(11/2) },    /* Indian Standard */
  461.     { "zp6",    tZONE,    -HOUR( 6) },      /* USSR Zone 5 */
  462. #if     0
  463.     /* For completeness.  NST is also Newfoundland Stanard, nad SST is
  464.      * also Swedish Summer. */
  465.     { "nst",    tZONE,    -HOUR(13/2) },    /* North Sumatra */
  466.     { "sst",    tZONE,    -HOUR( 7) },      /* South Sumatra, USSR Zone 6 */
  467. #endif  /* 0 */
  468.     { "wast",   tZONE,    -HOUR( 7) },      /* West Australian Standard */
  469.     { "wadt",   tDAYZONE, -HOUR( 7) },      /* West Australian Daylight */
  470.     { "jt",     tZONE,    -HOUR(15/2) },    /* Java (3pm in Cronusland!) */
  471.     { "cct",    tZONE,    -HOUR( 8) },      /* China Coast, USSR Zone 7 */
  472.     { "jst",    tZONE,    -HOUR( 9) },      /* Japan Standard, USSR Zone 8 */
  473.     { "cast",   tZONE,    -HOUR(19/2) },    /* Central Australian Standard */
  474.     { "cadt",   tDAYZONE, -HOUR(19/2) },    /* Central Australian Daylight */
  475.     { "east",   tZONE,    -HOUR(10) },      /* Eastern Australian Standard */
  476.     { "eadt",   tDAYZONE, -HOUR(10) },      /* Eastern Australian Daylight */
  477.     { "gst",    tZONE,    -HOUR(10) },      /* Guam Standard, USSR Zone 9 */
  478.     { "nzt",    tZONE,    -HOUR(12) },      /* New Zealand */
  479.     { "nzst",   tZONE,    -HOUR(12) },      /* New Zealand Standard */
  480.     { "nzdt",   tDAYZONE, -HOUR(12) },      /* New Zealand Daylight */
  481.     { "idle",   tZONE,    -HOUR(12) },      /* International Date Line East */
  482.     /* ADDED BY Marco Nijdam */
  483.     { "dst",    tDST,     HOUR( 0) },       /* DST on (hour is ignored) */
  484.     /* End ADDED */
  485.     {  NULL  }
  486. };
  487.  
  488. /*
  489.  * Military timezone table.
  490.  */
  491. static TABLE    MilitaryTable[] = {
  492.     { "a",      tZONE,  HOUR(  1) },
  493.     { "b",      tZONE,  HOUR(  2) },
  494.     { "c",      tZONE,  HOUR(  3) },
  495.     { "d",      tZONE,  HOUR(  4) },
  496.     { "e",      tZONE,  HOUR(  5) },
  497.     { "f",      tZONE,  HOUR(  6) },
  498.     { "g",      tZONE,  HOUR(  7) },
  499.     { "h",      tZONE,  HOUR(  8) },
  500.     { "i",      tZONE,  HOUR(  9) },
  501.     { "k",      tZONE,  HOUR( 10) },
  502.     { "l",      tZONE,  HOUR( 11) },
  503.     { "m",      tZONE,  HOUR( 12) },
  504.     { "n",      tZONE,  HOUR(- 1) },
  505.     { "o",      tZONE,  HOUR(- 2) },
  506.     { "p",      tZONE,  HOUR(- 3) },
  507.     { "q",      tZONE,  HOUR(- 4) },
  508.     { "r",      tZONE,  HOUR(- 5) },
  509.     { "s",      tZONE,  HOUR(- 6) },
  510.     { "t",      tZONE,  HOUR(- 7) },
  511.     { "u",      tZONE,  HOUR(- 8) },
  512.     { "v",      tZONE,  HOUR(- 9) },
  513.     { "w",      tZONE,  HOUR(-10) },
  514.     { "x",      tZONE,  HOUR(-11) },
  515.     { "y",      tZONE,  HOUR(-12) },
  516.     { "z",      tZONE,  HOUR(  0) },
  517.     { NULL }
  518. };
  519.  
  520.  
  521. /*
  522.  * Dump error messages in the bit bucket.
  523.  */
  524. static void
  525. yyerror(s)
  526.     char  *s;
  527. {
  528. }
  529.  
  530.  
  531. static time_t
  532. ToSeconds(Hours, Minutes, Seconds, Meridian)
  533.     time_t      Hours;
  534.     time_t      Minutes;
  535.     time_t      Seconds;
  536.     MERIDIAN    Meridian;
  537. {
  538.     if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
  539.         return -1;
  540.     switch (Meridian) {
  541.     case MER24:
  542.         if (Hours < 0 || Hours > 23)
  543.             return -1;
  544.         return (Hours * 60L + Minutes) * 60L + Seconds;
  545.     case MERam:
  546.         if (Hours < 1 || Hours > 12)
  547.             return -1;
  548.         return ((Hours % 12) * 60L + Minutes) * 60L + Seconds;
  549.     case MERpm:
  550.         if (Hours < 1 || Hours > 12)
  551.             return -1;
  552.         return (((Hours % 12) + 12) * 60L + Minutes) * 60L + Seconds;
  553.     }
  554.     return -1;  /* Should never be reached */
  555. }
  556.  
  557.  
  558. static int
  559. Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode, TimePtr)
  560.     time_t      Month;
  561.     time_t      Day;
  562.     time_t      Year;
  563.     time_t      Hours;
  564.     time_t      Minutes;
  565.     time_t      Seconds;
  566.     MERIDIAN    Meridian;
  567.     DSTMODE     DSTmode;
  568.     time_t     *TimePtr;
  569. {
  570.     static int  DaysInMonth[12] = {
  571.         31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  572.     };
  573.     time_t tod;
  574.     time_t Julian;
  575.     int i;
  576.  
  577.     DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
  578.                     ? 29 : 28;
  579.     if (Month < 1 || Month > 12
  580.      || Year < START_OF_TIME || Year > END_OF_TIME
  581.      || Day < 1 || Day > DaysInMonth[(int)--Month])
  582.         return -1;
  583.  
  584.     for (Julian = Day - 1, i = 0; i < Month; i++)
  585.         Julian += DaysInMonth[i];
  586.     if (Year >= EPOCH) {
  587.         for (i = EPOCH; i < Year; i++)
  588.             Julian += 365 + (i % 4 == 0);
  589.     } else {
  590.         for (i = Year; i < EPOCH; i++)
  591.             Julian -= 365 + (i % 4 == 0);
  592.     }
  593.     Julian *= SECSPERDAY;
  594.     Julian += yyTimezone * 60L;
  595.     if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
  596.         return -1;
  597.     Julian += tod;
  598.     if (DSTmode == DSTon
  599.      || (DSTmode == DSTmaybe && TclpGetDate(&Julian, 0)->tm_isdst))
  600.         Julian -= 60 * 60;
  601.     *TimePtr = Julian;
  602.     return 0;
  603. }
  604.  
  605.  
  606. static time_t
  607. DSTcorrect(Start, Future)
  608.     time_t      Start;
  609.     time_t      Future;
  610. {
  611.     time_t      StartDay;
  612.     time_t      FutureDay;
  613.  
  614.     StartDay = (TclpGetDate(&Start, 0)->tm_hour + 1) % 24;
  615.     FutureDay = (TclpGetDate(&Future, 0)->tm_hour + 1) % 24;
  616.     return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
  617. }
  618.  
  619.  
  620. static time_t
  621. RelativeDate(Start, DayOrdinal, DayNumber)
  622.     time_t      Start;
  623.     time_t      DayOrdinal;
  624.     time_t      DayNumber;
  625. {
  626.     struct tm   *tm;
  627.     time_t      now;
  628.  
  629.     now = Start;
  630.     tm = TclpGetDate(&now, 0);
  631.     now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
  632.     now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
  633.     return DSTcorrect(Start, now);
  634. }
  635.  
  636.  
  637. static int
  638. RelativeMonth(Start, RelMonth, TimePtr)
  639.     time_t Start;
  640.     time_t RelMonth;
  641.     time_t *TimePtr;
  642. {
  643.     struct tm *tm;
  644.     time_t Month;
  645.     time_t Year;
  646.     time_t Julian;
  647.     int result;
  648.  
  649.     if (RelMonth == 0) {
  650.         *TimePtr = 0;
  651.         return 0;
  652.     }
  653.     tm = TclpGetDate(&Start, 0);
  654.     Month = 12 * (tm->tm_year + TM_YEAR_BASE) + tm->tm_mon + RelMonth;
  655.     Year = Month / 12;
  656.     Month = Month % 12 + 1;
  657.     result = Convert(Month, (time_t) tm->tm_mday, Year,
  658.         (time_t) tm->tm_hour, (time_t) tm->tm_min, (time_t) tm->tm_sec,
  659.         MER24, DSTmaybe, &Julian);
  660.     /*
  661.      * The following iteration takes into account the case were we jump
  662.      * into a "short month".  Far example, "one month from Jan 31" will
  663.      * fail because there is no Feb 31.  The code below will reduce the
  664.      * day and try converting the date until we succed or the date equals
  665.      * 28 (which always works unless the date is bad in another way).
  666.      */
  667.  
  668.     while ((result != 0) && (tm->tm_mday > 28)) {
  669.     tm->tm_mday--;
  670.     result = Convert(Month, (time_t) tm->tm_mday, Year,
  671.         (time_t) tm->tm_hour, (time_t) tm->tm_min, (time_t) tm->tm_sec,
  672.         MER24, DSTmaybe, &Julian);
  673.     }
  674.     if (result != 0) {
  675.     return -1;
  676.     }
  677.     *TimePtr = DSTcorrect(Start, Julian);
  678.     return 0;
  679. }
  680.  
  681.  
  682. static int
  683. LookupWord(buff)
  684.     char                *buff;
  685. {
  686.     register char *p;
  687.     register char *q;
  688.     register TABLE *tp;
  689.     int i;
  690.     int abbrev;
  691.  
  692.     /*
  693.      * Make it lowercase.
  694.      */
  695.     for (p = buff; *p; p++) {
  696.         if (isupper(UCHAR(*p))) {
  697.             *p = (char) tolower(UCHAR(*p));
  698.     }
  699.     }
  700.  
  701.     if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
  702.         yylval.Meridian = MERam;
  703.         return tMERIDIAN;
  704.     }
  705.     if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
  706.         yylval.Meridian = MERpm;
  707.         return tMERIDIAN;
  708.     }
  709.  
  710.     /*
  711.      * See if we have an abbreviation for a month.
  712.      */
  713.     if (strlen(buff) == 3) {
  714.         abbrev = 1;
  715.     } else if (strlen(buff) == 4 && buff[3] == '.') {
  716.         abbrev = 1;
  717.         buff[3] = '\0';
  718.     } else {
  719.         abbrev = 0;
  720.     }
  721.  
  722.     for (tp = MonthDayTable; tp->name; tp++) {
  723.         if (abbrev) {
  724.             if (strncmp(buff, tp->name, 3) == 0) {
  725.                 yylval.Number = tp->value;
  726.                 return tp->type;
  727.             }
  728.         } else if (strcmp(buff, tp->name) == 0) {
  729.             yylval.Number = tp->value;
  730.             return tp->type;
  731.         }
  732.     }
  733.  
  734.     for (tp = TimezoneTable; tp->name; tp++) {
  735.         if (strcmp(buff, tp->name) == 0) {
  736.             yylval.Number = tp->value;
  737.             return tp->type;
  738.         }
  739.     }
  740.  
  741.     for (tp = UnitsTable; tp->name; tp++) {
  742.         if (strcmp(buff, tp->name) == 0) {
  743.             yylval.Number = tp->value;
  744.             return tp->type;
  745.         }
  746.     }
  747.  
  748.     /*
  749.      * Strip off any plural and try the units table again.
  750.      */
  751.     i = strlen(buff) - 1;
  752.     if (buff[i] == 's') {
  753.         buff[i] = '\0';
  754.         for (tp = UnitsTable; tp->name; tp++) {
  755.             if (strcmp(buff, tp->name) == 0) {
  756.                 yylval.Number = tp->value;
  757.                 return tp->type;
  758.             }
  759.     }
  760.     }
  761.  
  762.     for (tp = OtherTable; tp->name; tp++) {
  763.         if (strcmp(buff, tp->name) == 0) {
  764.             yylval.Number = tp->value;
  765.             return tp->type;
  766.         }
  767.     }
  768.  
  769.     /*
  770.      * Military timezones.
  771.      */
  772.     if (buff[1] == '\0' && isalpha(UCHAR(*buff))) {
  773.         for (tp = MilitaryTable; tp->name; tp++) {
  774.             if (strcmp(buff, tp->name) == 0) {
  775.                 yylval.Number = tp->value;
  776.                 return tp->type;
  777.             }
  778.     }
  779.     }
  780.  
  781.     /*
  782.      * Drop out any periods and try the timezone table again.
  783.      */
  784.     for (i = 0, p = q = buff; *q; q++)
  785.         if (*q != '.') {
  786.             *p++ = *q;
  787.         } else {
  788.             i++;
  789.     }
  790.     *p = '\0';
  791.     if (i) {
  792.         for (tp = TimezoneTable; tp->name; tp++) {
  793.             if (strcmp(buff, tp->name) == 0) {
  794.                 yylval.Number = tp->value;
  795.                 return tp->type;
  796.             }
  797.     }
  798.     }
  799.     
  800.     return tID;
  801. }
  802.  
  803.  
  804. static int
  805. yylex()
  806. {
  807.     register char       c;
  808.     register char       *p;
  809.     char                buff[20];
  810.     int                 Count;
  811.     int                 sign;
  812.  
  813.     for ( ; ; ) {
  814.         while (isspace((unsigned char) (*yyInput))) {
  815.             yyInput++;
  816.     }
  817.  
  818.         if (isdigit(c = *yyInput) || c == '-' || c == '+') {
  819.             if (c == '-' || c == '+') {
  820.                 sign = c == '-' ? -1 : 1;
  821.                 if (!isdigit(*++yyInput)) {
  822.                     /*
  823.              * skip the '-' sign
  824.              */
  825.                     continue;
  826.         }
  827.             } else {
  828.                 sign = 0;
  829.         }
  830.             for (yylval.Number = 0; isdigit(c = *yyInput++); ) {
  831.                 yylval.Number = 10 * yylval.Number + c - '0';
  832.         }
  833.             yyInput--;
  834.             if (sign < 0) {
  835.                 yylval.Number = -yylval.Number;
  836.         }
  837.             return sign ? tSNUMBER : tUNUMBER;
  838.         }
  839.         if (isalpha(UCHAR(c))) {
  840.             for (p = buff; isalpha(c = *yyInput++) || c == '.'; ) {
  841.                 if (p < &buff[sizeof buff - 1]) {
  842.                     *p++ = c;
  843.         }
  844.         }
  845.             *p = '\0';
  846.             yyInput--;
  847.             return LookupWord(buff);
  848.         }
  849.         if (c != '(') {
  850.             return *yyInput++;
  851.     }
  852.         Count = 0;
  853.         do {
  854.             c = *yyInput++;
  855.             if (c == '\0') {
  856.                 return c;
  857.         } else if (c == '(') {
  858.                 Count++;
  859.         } else if (c == ')') {
  860.                 Count--;
  861.         }
  862.         } while (Count > 0);
  863.     }
  864. }
  865.  
  866. /*
  867.  * Specify zone is of -50000 to force GMT.  (This allows BST to work).
  868.  */
  869.  
  870. int
  871. TclGetDate(p, now, zone, timePtr)
  872.     char *p;
  873.     unsigned long now;
  874.     long zone;
  875.     unsigned long *timePtr;
  876. {
  877.     struct tm *tm;
  878.     time_t Start;
  879.     time_t Time;
  880.     time_t tod;
  881.     int thisyear;
  882.  
  883.     yyInput = p;
  884.     tm = TclpGetDate((time_t *) &now, 0);
  885.     thisyear = tm->tm_year + TM_YEAR_BASE;
  886.     yyYear = thisyear;
  887.     yyMonth = tm->tm_mon + 1;
  888.     yyDay = tm->tm_mday;
  889.     yyTimezone = zone;
  890.     if (zone == -50000) {
  891.         yyDSTmode = DSToff;  /* assume GMT */
  892.         yyTimezone = 0;
  893.     } else {
  894.         yyDSTmode = DSTmaybe;
  895.     }
  896.     yyHour = 0;
  897.     yyMinutes = 0;
  898.     yySeconds = 0;
  899.     yyMeridian = MER24;
  900.     yyRelSeconds = 0;
  901.     yyRelMonth = 0;
  902.     yyHaveDate = 0;
  903.     yyHaveDay = 0;
  904.     yyHaveRel = 0;
  905.     yyHaveTime = 0;
  906.     yyHaveZone = 0;
  907.  
  908.     if (yyparse() || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 ||
  909.         yyHaveDay > 1) {
  910.         return -1;
  911.     }
  912.     
  913.     if (yyHaveDate || yyHaveTime || yyHaveDay) {
  914.     if (TclDateYear < 0) {
  915.         TclDateYear = -TclDateYear;
  916.     }
  917.     /*
  918.      * The following line handles years that are specified using
  919.      * only two digits.  The line of code below implements a policy
  920.      * defined by the X/Open workgroup on the millinium rollover.
  921.      * Note: some of those dates may not actually be valid on some
  922.      * platforms.  The POSIX standard startes that the dates 70-99
  923.      * shall refer to 1970-1999 and 00-38 shall refer to 2000-2038.
  924.      * This later definition should work on all platforms.
  925.      */
  926.  
  927.     if (TclDateYear < 100) {
  928.         if (TclDateYear >= 69) {
  929.         TclDateYear += 1900;
  930.         } else {
  931.         TclDateYear += 2000;
  932.         }
  933.     }
  934.     if (Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
  935.         yyMeridian, yyDSTmode, &Start) < 0) {
  936.             return -1;
  937.     }
  938.     } else {
  939.         Start = now;
  940.         if (!yyHaveRel) {
  941.             Start -= ((tm->tm_hour * 60L) + tm->tm_min * 60L) + tm->tm_sec;
  942.     }
  943.     }
  944.  
  945.     Start += yyRelSeconds;
  946.     if (RelativeMonth(Start, yyRelMonth, &Time) < 0) {
  947.         return -1;
  948.     }
  949.     Start += Time;
  950.  
  951.     if (yyHaveDay && !yyHaveDate) {
  952.         tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
  953.         Start += tod;
  954.     }
  955.  
  956.     *timePtr = Start;
  957.     return 0;
  958. }
  959.